import {
  computed,
  defineComponent,
  reactive,
  ref,
  toRef,
  toRefs,
  watch,
} from "vue";
import style from "./index.module.less";
import {
  IFormData,
  IFormItem,
  IFormRulesRegular,
  IFormRulesRequired,
  IFormTypeData,
} from "./types";
const module = import.meta.globEager("./Components/**/*.tsx");
import { formDataControl } from "@/command/apiTool";

export default defineComponent({
  name: "form-view",
  props: {
    data: {
      type: Array as () => IFormItem[],
      default: () => [],
    },
    modelValue: {
      type: Object,
      default: () => {},
    },
    typeData: {
      type: Object,
      default: () => {},
    },
  },
  emits: ["update:modelValue"],
  setup(props, { expose, emit }) {
    let formData = reactive(props.modelValue || {});
    watch(
      () => props.modelValue,
      (newValue) => {
        // console.log("更新");
        formData = Object.assign(formData, newValue);
      },
      {
        deep: true,
      }
    );
    const layers = reactive<Record<string, any>>({});
    return () => {
      function getValue(item: IFormItem & { keys: string[] }) {
        if (item.keys) {
          return item.keys.map((e) => formData[e]);
        } else {
          return (formData as any)[item.key!];
        }
      }
      function getComponents(item: IFormItem) {
        try {
          return module[`./Components/${item.type}/index.tsx`].default;
        } catch (error) {
          return null;
        }
      }
      function getRequired(item: IFormItem) {
        return (item.rules || [])?.some((rule: any) => rule.required);
      }
      function renderLabel(item: IFormItem) {
        if (!item.label) return null;
        return (
          <div
            class={[
              "text-[17px] flex items-center text-[#333]",
              getRequired(item) && style.required,
            ]}
          >
            {item.label}
          </div>
        );
      }
      function onChange(item: IFormItem & { keys: string[] }, value: any) {
        // console.log("item.keys", item.keys, value);
        if (item.keys) {
          item.keys.forEach((e, i) => {
            formData[e] = value[i];
          });
          emit("update:modelValue", formData);
        } else {
          formData[item.key!] = value;
          emit("update:modelValue", formData);
        }
      }
      function setLayers(key: any, value: any) {
        layers[key] = value;
      }
      function getItemClass(
        { layer = "horizontal", key = "", type = "" } = {} as Pick<
          IFormItem,
          "layer" | "key" | "type"
        >
      ) {
        let layersType = layer;
        if (layers[key]) layersType = layers[key];
        if (layersType == "horizontal") {
          switch (type) {
            case "uploadPopup":
            case "upload":
            case "textarea":
              return [style.horizontal, style.lineFeed];
            case "switch":
              return [style.horizontal, style.switch];
          }
          return style.horizontal;
        } else {
          return style.vertical;
        }
      }
      function getTypeData(item: IFormItem & { typeData: IFormTypeData }) {
        return item.typeData ? item.typeData : [];
      }
      function renderItem(item: IFormItem) {
        const Components = getComponents(item);
        return (
          <div class={getItemClass(item)}>
            {renderLabel(item)}
            <div>
              <Components
                item={item}
                modelValue={getValue(item as any)}
                onChange={(value: any) => onChange(item as any, value)}
                setLayers={(value: any) => setLayers(item.key, value)}
                typeData={getTypeData(item as any)}
              />
            </div>
          </div>
        );
      }
      function renderComponents() {
        return props.data.map((e) => {
          return renderItem(e as any);
        });
      }
      const submitData = (
        key: string,
        {
          message,
          error,
          result,
          label,
        }: { message: string; error: any; result: any; label: any }
      ) => {
        if (!props.modelValue[key]) {
          error[key] = message || "请输入" + label;
        } else if (Array.isArray(props.modelValue[key])) {
          const invalidItems = props.modelValue[key].filter(
            (item: any) => !(item && item.toString().match(/^.*$/))
          );
          if (invalidItems.length > 0) {
            error[key] = message || "请输入" + label;
          } else {
            result[key] = props.modelValue[key];
          }
        } else if (
          (
            (props.data.find((e) => e.key === key)?.rules ||
              []) as IFormRulesRegular[]
          ).some((el) => {
            return (
              el.regular &&
              !props.modelValue[key]
                .toString()
                .match((el as IFormRulesRegular).regular!)
            );
          })
        ) {
          error[key] = message || "请输入" + label;
        } else {
          result[key] = props.modelValue[key];
        }
      };

      const submit = (callBack: any, isFromGroup: boolean) => {
        return new Promise<{ result: any; error: any }>((resolve) => {
          let error: any = {};
          let result: any = {};
          props.data.forEach((e) => {
            if (e.rules) {
              const rules = e.rules.filter(
                (el: IFormRulesRequired) =>
                  el.required || (el as IFormRulesRegular).regular
              );
              if (rules.length === 0) {
                return;
              }
              let state = true;
              if ((e as any).keys) {
                (e as any).keys.forEach((ea: string) => {
                  submitData(ea, {
                    message: (
                      rules.find((el) => (el as IFormRulesRequired).required) ||
                      rules[0]
                    ).message!,
                    error,
                    result,
                    label: e.label,
                  });
                  if (error[ea]) {
                    state = false;
                  }
                });
              } else if (e.key) {
                submitData(e.key as string, {
                  message: (
                    rules.find((el) => (el as IFormRulesRequired).required) ||
                    rules[0]
                  ).message!,
                  error,
                  result,
                  label: e.label,
                });
                if (error[e.key]) {
                  state = false;
                }
              }
              if (!state) {
                return;
              }
            }
          });
          if (callBack) {
            callBack &&
              callBack(
                isFromGroup
                  ? { result, error }
                  : formDataControl({ result, error })
              );
          } else {
            resolve(
              isFromGroup
                ? { result, error }
                : formDataControl({ result, error })
            );
          }
        });
      };
      expose({
        submit,
      });
      return (
        <div class={"flex flex-col bg-white form"}>{renderComponents()}</div>
      );
    };
  },
});
